
#include "ev_timer.h"
#include <event2/event_struct.h>

void EvTimer::event_timer_cb(evutil_socket_t fd, short event, void *arg)
{
    EvTimer *ev = (EvTimer *)arg;
    if (ev->onTimeout_) {
        ev->onTimeout_();
    }
    if (ev->auto_delete_) {
        delete ev;
    }
}

EvTimer::EvTimer(uint32_t time_ms)
{
    auto ev_base_ = EvBase::getInstance();
    timeout_.tv_sec = time_ms / 1000;
    timeout_.tv_usec = (time_ms % 1000) * 1000;
    event_ = event_new(ev_base_->get_base(), -1, 0, event_timer_cb, this);
    auto_delete_ = false;
}

EvTimer::~EvTimer()
{
    if (event_) {
        event_free(event_);
    }
}

EvTimer::EvTimer(EvTimer&& other) noexcept :
    event_(std::exchange(other.event_, nullptr)),
    timeout_(other.timeout_),
    onTimeout_(std::move(other.onTimeout_)),
    auto_delete_(other.auto_delete_)
{
    if (event_) {
        auto ev_base_ = EvBase::getInstance();
        event_del(event_);
        event_assign(event_, ev_base_->get_base(), -1, 0, event_timer_cb, this);
    }
}

EvTimer& EvTimer::operator=(EvTimer&& other) noexcept
{
    if (this != &other) {
        if (event_) {
            event_free(event_);
        }
        event_ = std::exchange(other.event_, nullptr);
        timeout_ = other.timeout_;
        onTimeout_ = std::move(other.onTimeout_);
        auto_delete_ = other.auto_delete_;
        if (event_) {
            auto ev_base_ = EvBase::getInstance();
            event_del(event_);
            event_assign(event_, ev_base_->get_base(), -1, 0, event_timer_cb, this);
        }
    }
    return *this;
}


int EvTimer::setCallBack(std::function<void()> cb)
{
    onTimeout_ = cb;
    return 0;
}

int EvTimer::start()
{
    if (timeout_.tv_sec == 0 && timeout_.tv_usec == 0) {
        return -1;
    }
    if (!event_) {
        return -2;
    }
    event_add(event_, &timeout_);
    return 0;
}

int EvTimer::start(uint32_t time_ms)
{
    if (time_ms == 0) {
        return -1;
    }
    if (!event_) {
        return -2;
    }
    timeout_.tv_sec = time_ms / 1000;
    timeout_.tv_usec = (time_ms % 1000) * 1000;
    event_add(event_, &timeout_);
    return 0;
}

int EvTimer::stop()
{
    if (!event_) {
        return -1;
    }
    event_del(event_);
    return 0;
}

int EvTimer::setAutoDelete(bool auto_delete)
{
    auto_delete_ = auto_delete;
    return 0;
}
